/*
 * Copyright (c) 2023 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "module_common_core_inner.h"

#include <stddef.h>

#include "logger.h"
#include "parcel.h"

ResultCode SeServiceStatusFromRspApdu(const uint8_t *response, uint32_t length, SeServiceStatus *output)
{
    if (response == NULL || output == NULL) {
        return INVALID_PARA_NULL_PTR;
    }

    if (length < MIN_APDU_RESP_SIZE) {
        LOG_ERROR("rsp len is %u", length);
        return INVALID_PARA_ERR_SIZE;
    }

    uint8_t sw1 = response[length - 2];
    uint8_t sw2 = response[length - 1];
    uint16_t statusWords = (uint16_t)sw1 * 256 + (uint16_t)sw2;
    if (statusWords != SW_NO_ERROR) {
        LOG_ERROR("rsp len is 0x%x", statusWords);
        return RES_APDU_SW_ERR;
    }

    // if sw is 0x9000, the applet is available
    output->available = 1;

    if (length == MIN_APDU_RESP_SIZE) {
        LOG_INFO("leagcy applet, rsp len is %u", length);
        return SUCCESS;
    }

    Parcel parcel = CreateParcelWithData(response, length);

    do {
        // 2-bytes version
        uint16_t version = 0;
        if (!ParcelReadUint16(&parcel, &version)) {
            LOG_ERROR("read version error");
            break;
        }

        output->version = version;

        // 4-bytes vendor
        if (!ParcelReadUint32(&parcel, &output->config.vendor)) {
            LOG_ERROR("read vendor error");
            break;
        }

        // 12-bytes config
        if (!ParcelRead(&parcel, output->config.config, SERVICE_STATUS_MAX_CONFIG_LEN)) {
            LOG_ERROR("read config error");
            break;
        }

        // 8-bytes status, could be failed in some applet
        (void)ParcelRead(&parcel, output->status, SERVICE_STATUS_DATA_LEN);
    } while (0);

    DeleteParcel(&parcel);

    return SUCCESS;
}